import { h } from 'vue'
import { BaseModel } from '@/hooks/useModel'
import {
  CreateInputComponentParam,
  EFormInst,
  EFormProps,
  EModelCommProps,
  EModelState,
  EQueryProps,
  ETableInst,
  ETableProps,
  LoadData
} from '@/components/ext/types'
import { DataTableInst, FormInst, NDatePicker, NInput, NSwitch, NTimePicker } from 'naive-ui'
import type { EzModelOptions, FormDataType, IFormData, InputType } from 'easy-descriptor'
import { BaseModelConstructor, FormDataTypeEnum, FormTypeEnum, InputTypeEnum, useModelOptions } from 'easy-descriptor'
import { useModelApi } from '@/hooks/useApi'
import { cloneDeep } from 'lodash-es'
import EDictInput from '@/components/ext/input/EDictInput.vue'

export const usePanel = <T extends BaseModel>(instance: BaseModelConstructor<T>, cProps?: EModelCommProps<T>): EModelState<T> => {
  // const tableRef = ref<DataTableInst>()
  const tableRef = ref<ETableInst<T>>()
  const nTableRef = ref<DataTableInst>()
  const formRef = ref<EFormInst<T>>()
  const nFormRef = ref<FormInst>()
  const queryRef = ref<EFormInst<T>>()
  const nQueryRef = ref<FormInst>()

  const modelOptions: EzModelOptions<T> = useModelOptions<T>(instance)
  const { page: loadPage } = useModelApi<T>(modelOptions.api)
  Object.keys(modelOptions.fields)?.forEach((key) => {
    if (!modelOptions.fields[key].dataType) {
      const metadata = Reflect.getMetadata('design:type', instance.prototype, key)
      // console.log(`${key}: dataType = `, metadata)
      modelOptions.fields[key].dataType = metadata?.name?.toLowerCase()
      !modelOptions.fields[key].inputType && (modelOptions.fields[key].inputType = dataTypeToInputType(modelOptions.fields[key].dataType))
    }
  })

  const loadData: LoadData<T> = async (param?: any) => {
    // tableLoading.value = true
    const pagination = tableRef.value?.getPageParams?.() || {}
    const queryData = queryRef.value?.getFormData() || {}
    const { pageSize, page, sort } = pagination
    const params = {
      size: pageSize,
      current: page,
      sort,
      ...(queryData || {}),
      ...param
    }
    console.log('params --> ', params)
    const resp = await loadPage(params).catch((err) => {
      return Promise.reject(err || new Error('数据加载失败'))
    })
    return resp.data
  }

  // const showForm = async (formData: any, type?: FormType) => {
  //   console.log('formData --> ', formData)
  //   const _formData = config?.formatFormData ? await config.formatFormData(formData) : formData
  //   formRef.value!.open(type!, _formData)
  //   return _formData
  // }

  const reload: LoadData<T> = async (params?: any) => {
    return await tableRef.value!.reload(params)
  }

  const tableProps: ETableProps<T> = {
    'onUpdate:bindRef': (val: DataTableInst) => {
      nTableRef.value = val
    },
    loadData,
    instance,
    formInst: formRef,
    modelOptions: cloneDeep(modelOptions),
    ...cProps?.tableProps
    // onShowForm: showForm
    // 'on-show-form': showFormAndFormat
  }

  const defAddFormData = () => {
    const defData = {}
    for (const key in modelOptions.fields) {
      const { defaultValue } = modelOptions.fields[key]
      defaultValue && (defData[key] = defaultValue)
    }
    return defData
  }

  const formProps: EFormProps<T> = {
    'onUpdate:bindRef': (val: FormInst) => {
      nFormRef.value = val
    },
    instance,
    defaultData: defAddFormData(),
    modelOptions: cloneDeep(modelOptions),
    // formatFormData: config?.formatFormData as FormatFormData<T>,
    // beforeSubmit: config?.beforeSubmit as FormatFormData<T>,
    onSuccess: async () => {
      tableRef.value && (await reload())
    },
    ...cProps?.formProps
    // 'on-show-form': showFormAndFormat
  }
  const queryProps: EQueryProps<T> = {
    'onUpdate:bindRef': (val: FormInst) => {
      nFormRef.value = val
    },
    loadData: reload,
    formProps: {
      labelWidth: 80
    },
    instance,
    modelOptions: cloneDeep(modelOptions),
    ...cProps?.queryProps
  }

  return {
    refs: {
      tableRef,
      nTableRef,
      formRef,
      nFormRef,
      queryRef,
      nQueryRef
    },
    modelOptions,
    commProps: {
      tableProps,
      formProps,
      queryProps
    },
    loadData
    // showForm
  }
}

const dataTypeToInputType = (dataType: FormDataType): InputType => {
  switch (dataType) {
    case FormDataTypeEnum.NUMBER:
      return InputTypeEnum.INPUT_NUMBER
    case FormDataTypeEnum.DATE:
      return InputTypeEnum.DATE
    case FormDataTypeEnum.TIME:
      return InputTypeEnum.TIME
    case FormDataTypeEnum.DATETIME:
      return InputTypeEnum.DATETIME
    case FormDataTypeEnum.BOOLEAN:
      return InputTypeEnum.SWITCH
    default:
      return InputTypeEnum.TEXT
  }
}

export function createInputComponent<T extends BaseModel>(param: CreateInputComponentParam<T>): VNode {
  // console.log('createInputComponent', param)
  const { field, formData, formType, props } = param
  const { key, path, label, inputType, dataType, inputProps = {}, queryInputProps = {}, disabled, disabledHandler } = field
  const { formCompProps = {} } = field

  const query = formType === FormTypeEnum.SEARCH
  let component: any
  const dataKey = (path || key || '').toString() as keyof IFormData<T>
  if (!formData.value) {
    formData.value = {}
  }
  const fieldValue = formData.value[dataKey]
  // const refFormData = ref<IFormData<T>>(formData)
  const compProps: Record<string, any> = {
    placeholder: label,
    value: fieldValue === undefined ? null : fieldValue,
    'onUpdate:value': (val: any) => {
      formData.value![dataKey] = val
    },
    clearable: true,
    filterable: true,
    showButton: formType !== FormTypeEnum.EDIT_TABLE,
    ...inputProps,
    ...(query ? queryInputProps : {}),
    ...(props || {}),
    ...formCompProps
  }

  function isFormDisabled(): boolean {
    if (query) return false
    if (!disabled) return false
    if (typeof disabled === 'boolean') return disabled
    let flag = false
    if (Array.isArray(disabled)) {
      flag = disabled.some((item) => [formType, 'form'].includes(item))
    }
    if (typeof disabledHandler === 'function') {
      const safeFormData = (formData.value as IFormData<T>) || {}
      return disabledHandler(safeFormData, formType) || flag
    }
    return flag
  }

  compProps.disabled = isFormDisabled()

  const dict = field.dict
  if (!!dict) {
    component = EDictInput
    compProps.code = dict
    const { component: comp = inputType } = query ? queryInputProps : inputProps
    compProps.component = query && inputType === 'switch' ? 'select' : comp
    compProps.clearable = true
    compProps.multiple = !query && dataType === FormDataTypeEnum.ARRAY
    formType === FormTypeEnum.EDIT_TABLE && (compProps.showButton = false)
  } else {
    switch (inputType) {
      case InputTypeEnum.INPUT_NUMBER:
        component = NInputNumber
        break
      case InputTypeEnum.TEXT_AREA:
        component = NInput
        compProps.type = 'textarea'
        break
      case InputTypeEnum.DATE:
        component = NDatePicker
        compProps.type = 'date'
        // console.log("compProps['value-format'] ----- ", compProps['value-format'])
        // !compProps['value-format'] && (compProps['value-format'] = 'yyyy-MM-dd')
        // compProps['formatted-value'] = compProps.value
        // compProps['on-update:formatted-value'] = compProps['on-update:value']
        // delete compProps.value
        // delete compProps['on-update:value']
        break
      case InputTypeEnum.DATETIME:
        component = NDatePicker
        compProps.type = 'datetime'
        break
      case InputTypeEnum.TIME:
        component = NTimePicker
        compProps.timeZone = 'Asia/Shanghai'
        break
      case InputTypeEnum.SWITCH:
        component = NSwitch
        break
      default:
        component = NInput
        break
    }
  }
  // console.log('compProps -->', compProps)
  return h(component, compProps)
}
